using System;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;

using Jeffrey.XFramework.XCrawl;

namespace Jeffrey.XProcess
{
    public class MemoryOptimizedUriContainer : MemoryUriContainer
    {
        public MemoryOptimizedUriContainer()
            :base()
        {
            m_SegmentTable = new Dictionary<UInt32, String>();
        }

        private static readonly Int32 s_OptLevel = 2;

        protected override String innerGetNext()
        {
            String curi = base.innerGetNext();

            if (curi == null ||
                curi == String.Empty
               )
                return curi;

            Boolean addSlash = false;
            StringBuilder optString = new StringBuilder(String.Empty);

            if (curi.EndsWith("\n"))
            {
                addSlash = true;
                curi = curi.Remove(curi.Length - 1);
            }

            String[] segments = curi.Split(new Char[] { '\n' });

            //the scheme of uri...
            optString.Append(m_SegmentTable[UInt32.Parse(segments[0])] + "://");

            for (Int32 index = 1, opt = s_OptLevel; index < segments.Length; index++, opt--)
            {
                if (index + 1 == segments.Length)
                {
                    if (opt == 0)
                        optString.Append(segments[index]);
                    else
                        optString.Append(m_SegmentTable[UInt32.Parse(segments[index])]);
                }
                else
                    optString.Append(m_SegmentTable[UInt32.Parse(segments[index])] + "/");
            }

            if (addSlash)
                optString.Append('/');

            return optString.ToString();
        }

        protected override void innerSchedule(String curi)
        {
            curi = ConvertUriToOpt(curi);
            if( curi != null &&
                curi != String.Empty
               ) 
               base.innerSchedule(curi);
        }

        protected override void Release()
        {
            m_SegmentTable.Clear();
            base.Release();
        }

        private String ConvertUriToOpt(String suri)
        {
            if (suri == null ||
                suri == String.Empty
               )
                return suri;

            String[] segments = null;
            UInt32   hash     = 0;
            StringBuilder optString = new StringBuilder(String.Empty);

            segments = suri.Split(new String[] { "://" }, StringSplitOptions.None);
            if (segments.Length <= 1 ||
                segments[1] == String.Empty
               )
                return String.Empty;

            //hash the uri's scheme...
            hash = CrawlToolKits.StringHash(segments[0]);
            m_SegmentTable[hash] = segments[0];
            optString.Append(hash.ToString() + "\n");

            suri = segments[1];

            Int32 bslash = 0;
            Int32 eslash = 0;
            Int32 parts = s_OptLevel;

            eslash = suri.IndexOf("/", bslash);
            while (parts > 0 && eslash != -1)
            {
                String seg = suri.Substring(bslash, eslash - bslash);

                hash = CrawlToolKits.StringHash(seg);
                if (!m_SegmentTable.ContainsKey(hash))
                    m_SegmentTable[hash] = seg;
                optString.Append(hash.ToString() + "\n");

                parts--;
                bslash = eslash + 1;
                eslash = suri.IndexOf("/", bslash);
            }

            if (parts > 0)
            {
                String seg = suri.Substring(bslash);

                if (seg != String.Empty)
                {
                    hash = CrawlToolKits.StringHash(seg);
                    if (!m_SegmentTable.ContainsKey(hash))
                        m_SegmentTable[hash] = seg;
                    optString.Append(hash.ToString());
                }
            }
            else
                optString.Append(suri.Substring(bslash));

            return optString.ToString();
        }

        private Dictionary<UInt32, String> m_SegmentTable;
    }
}